<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2019/3/13
 * Time: 15:46
 */

namespace core\db;


use core\Config;
use PDO;

class MysqlModel
{
    protected static $instance;
    private $pdo;
    private $table;

    private $where;
    private $join;
    private $group;
    private $order;
    private $field;
    private $page;
    private $size;
    private $sql;
    private $alias;
    private $arg;
    public function __construct($table)
    {
        $config = Config::getInstance()->getConfig('database');
        $dsn = "mysql:host=".$config['hostname'].";port=".($config['hostport']?:3306).";dbname=".$config['database'].";charset=".$config['charSet'];
        $this->pdo = new PDO($dsn,$config['username'], $config['password'], array(PDO::ATTR_PERSISTENT => true,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
        $this->table = toUnderScore($table);
    }

    public function alias($alias)
    {
        $this->alias = $alias;
    }

    public function startTrans()
    {
        $this->pdo->beginTransaction();
    }

    public function where($wheres)
    {
        if (is_array($wheres)){
            $whereSql = '(';
            foreach ($wheres as $where){
                list($field,$exp,$value) = $where;
                if (is_array($value) && $exp == 'in'){
                    $value = '('.implode(',',$value).')';
                }
                if (is_array($value) && count($value) == 2 && $exp == 'between'){
                    $value = implode(' and ',$value);
                }
                if (strpos($field,'|')){
                    $fields = explode('|',$field);
                    $str = '(';
                    foreach ($fields as $f){
                        if ($exp == 'in'){
                            $str .= $f . ' ' . $this->analysisExp($exp) . ' ' . $value . ' or ';
                        }else{
                            $str .= $f . ' ' . $this->analysisExp($exp) . ' :' . $f . ' or ';
                            $this->arg[$f]=$value;
                        }
                    }
                    $str = substr($str,0,-3) . ')';
                }else{
                    if ($exp == 'in'){
                        $str = $field . ' ' . $this->analysisExp($exp) . ' ' . $value . ' ';
                    }else{
                        $str = $field . ' ' . $this->analysisExp($exp) . ' :' . $field . ' ';
                        $this->arg[$field]=$value;
                    }
                }
                $whereSql .= $str . ' and ';
            }
            $whereSql = substr($whereSql,0,-5) . ') ';
        }
        if (is_null($this->where)){
            $this->where = $whereSql;
        }else{
            $this->where .= ' and ' . $whereSql;
        }
        return $this;
    }


    /**
     * @param $table string
     * @param $on string
     * @param string $type
     */
    public function join($table,$on,$type='inner')
    {
        if (is_null($this->join)){
            $this->join = ' '.$type.' join '.$table.' on '.$on.' ';
        }else{
            $this->join .= ' '.$type.' join '.$table.' on '.$on.' ';
        }
    }

    public function order($order)
    {
        $this->order = $order;
    }

    /**
     * group by
     * @param $group
     */
    public function group($group)
    {
        if (is_array($group)){
            $this->group = implode(',',$group);
        }else{
            $this->group = $group;
        }
    }

    /**
     * 设置查询字段
     * @param string|array $field
     */
    public function field($field = '')
    {
        if (is_array($field)){
            $this->field = implode(',',$field);
        }else{
            $this->field = $field;
        }
    }

    /**
     * 设置查找页数
     * @param $page int
     * @return $this|null
     */
    public function page($page)
    {
        if (is_null($this->page)) {
            $this->page = $page;
            return $this;
        }
        return null;
    }

    /** 设置每页显示数据量
     * @param $size int
     * @return $this|null
     */
    public function size($size)
    {
        if (is_null($this->size)) {
            $this->size = $size;
            return $this;
        }
        return null;
    }

    /**
     * 查找单个
     */
    public function find()
    {
        $this->page = 1;
        $this->size = 1;
        $this->splicingSql();
        $result = $this->pdo->prepare($this->sql);
        debug_log($this->arg,'sql in arg');
        $result->execute($this->arg);
        if ($result->errorCode() != '00000'){
            throw new \Exception($result->errorInfo()[2],$result->errorInfo()[0]);
        }
        $data = $result->fetch();
        if ($data)
            foreach ($data as $key => $datum){
                if (is_numeric($key)){
                    unset($data[$key]);
                }
            }
        return $data;
    }

    /**
     * 批量查找
     * @return array
     * @throws \Exception
     */
    public function select()
    {
        $this->splicingSql();
        $result = $this->pdo->prepare($this->sql);
        $result->execute($this->arg);
        if ($result->errorCode() != '00000'){
            throw new \Exception($result->errorInfo()[2],$result->errorInfo()[0]);
        }
        $data = $result->fetchAll();
        foreach ($data as $key => $datum){
            foreach ($datum as $k =>$item){
                if (is_numeric($k)){
                    unset($data[$key][$k]);
                }
            }
        }
        return $data;
    }

    /**
     * 拼装sql
     */
    protected function splicingSql()
    {
        if (is_null($this->field)){
            $this->field = '*';
        }
        if (!is_null($this->alias)){
            $this->table .= ' '.$this->alias;
        }
        $this->sql = 'select '.$this->field.' from '.$this->table;
        if (!is_null($this->join)){
            $this->sql .= ' ' .$this->join;
        }
        if (!is_null($this->where)){
            $this->sql .= ' where '.$this->where;
        }
        if (!is_null($this->group)){
            $this->sql .= ' group by '.$this->group;
        }
        if (!is_null($this->order)){
            $this->sql .= ' order by '.$this->order;
        }
        if (!is_null($this->page) && !is_null($this->size)){
            $this->sql .= ' limit '.($this->page-1) * $this->size .','.$this->page * $this->size;
        }
        debug_log($this->sql ,' sql ');
    }

    public function analysisExp($exp)
    {
        switch (trim($exp)){
            case '<>':
            case '!=':
            case 'NEQ':
                return '<>';
            case 'exp':
            case '':
            case 'is':
                return '';
            default:return $exp;
        }
    }
}